﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Probability;

namespace SAUlot
{
    public class AirplaneControler
    {

        private ManualResetEvent endEvent;
        private Thread airplaneThread;
        private AirplaneModel airplaneModel;
        private ASampler Sampler;
        public AirplaneActorCritic AAC3;
        public AirplaneACRepeated AACR3;
        public AirplaneActorCritic AAC4;
        public AirplaneACRepeated AACR4;
        private double[] steering;
        private int counter;
        private int counter_2;
        private const int time = 20;
        private int withRepeat = 0;
        private int threeVar = 0;
        private Reinforcement.CCDecisionMaker[,] algorithms;
        public AirplaneControler(RaportForm new_raport)
        {
            raport = new_raport;
            steering = new double[1];
            counter = 0;
            counter_2 = 0;
            Sampler = new ASampler();
            algorithms = new Reinforcement.CCDecisionMaker[2, 2];
            ///////////////////////////wejscia wyjscia  beta_fi   beta_v     gamma  std_dev neurony  2 warstwa aktora                2warstwa krytyka
            AAC3 =  new AirplaneActorCritic(3,    1,     0.000005,    0.000002,    0.8,   0.2,   400,   Neural.CellType.Arcustangent, Neural.CellType.Linear);
            AACR3 = new AirplaneACRepeated (3,    1,     0.000005,    0.000002,    0.8,   0.2,   400,   Neural.CellType.Arcustangent, Neural.CellType.Linear);
            AAC4 = new AirplaneActorCritic(4, 1, 0.000005, 0.000002, 0.8, 0.2, 400, Neural.CellType.Arcustangent, Neural.CellType.Linear);
            AACR4 = new AirplaneACRepeated(4, 1, 0.000005, 0.000002, 0.8, 0.2, 400, Neural.CellType.Arcustangent, Neural.CellType.Linear);
            algorithms[0, 0] = AAC3;
            algorithms[0, 1] = AACR3;
            algorithms[1, 0] = AAC4;
            algorithms[1, 1] = AACR4;
            AACR3.RaportAppend += new RaportForm.RaportThis(new RaportForm.RaportThis(raport.RaportHandler));
            AACR3.RaportClearCharts += new RaportForm.RaportClear(new RaportForm.RaportClear(raport.RaportClearHandler));
            AACR3.RaportSetTitle += new RaportForm.RaportTitle(new RaportForm.RaportTitle(raport.RaportTitleHandler));
            AACR3.RaportSetStep += new RaportForm.RaportStep(new RaportForm.RaportStep(raport.RaportStepHandler));
            
            AAC3.RaportAppend += new RaportForm.RaportThis(new RaportForm.RaportThis(raport.RaportHandler));
            AAC3.RaportClearCharts += new RaportForm.RaportClear(new RaportForm.RaportClear(raport.RaportClearHandler));
            AAC3.RaportSetTitle += new RaportForm.RaportTitle(new RaportForm.RaportTitle(raport.RaportTitleHandler));
            AAC3.RaportSetStep += new RaportForm.RaportStep(new RaportForm.RaportStep(raport.RaportStepHandler));

            AACR4.RaportAppend += new RaportForm.RaportThis(new RaportForm.RaportThis(raport.RaportHandler));
            AACR4.RaportClearCharts += new RaportForm.RaportClear(new RaportForm.RaportClear(raport.RaportClearHandler));
            AACR4.RaportSetTitle += new RaportForm.RaportTitle(new RaportForm.RaportTitle(raport.RaportTitleHandler));
            AACR4.RaportSetStep += new RaportForm.RaportStep(new RaportForm.RaportStep(raport.RaportStepHandler));

            AAC4.RaportAppend += new RaportForm.RaportThis(new RaportForm.RaportThis(raport.RaportHandler));
            AAC4.RaportClearCharts += new RaportForm.RaportClear(new RaportForm.RaportClear(raport.RaportClearHandler));
            AAC4.RaportSetTitle += new RaportForm.RaportTitle(new RaportForm.RaportTitle(raport.RaportTitleHandler));
            AAC4.RaportSetStep += new RaportForm.RaportStep(new RaportForm.RaportStep(raport.RaportStepHandler));

            AAC3.Init();
            AACR3.Init();
            AAC4.Init();
            AACR4.Init();
        }

        public AirplaneModel Model
        {
            get { return airplaneModel; }
            set { airplaneModel = value; }
        }
        public void HardReset()
        {
            //czyszczenie baz algorytmów
            AAC3.Init();
            AACR3.Init();
            AAC4.Init();
            AACR4.Init();
        }

        public int SetActorCritic
        {
            get { return withRepeat; }
            set 
            { 
                HardReset(); 
                withRepeat = value;
            }
        }

        public int SetVariableNumber
        {
            get { return threeVar; }
            set
            {
                HardReset();
                threeVar = value;
            }
        }

        private AirplaneView airplaneView;
        public AirplaneView View
        {
            get { return airplaneView; }
            set
            {
                airplaneView = value;
                airplaneModel.CCMoveEvent += new Reinforcement.CCActionHandler(airplaneView.UpdateState);
            }
        }

        private RaportForm raport;
        public RaportForm Raport
        {
            get { return raport; }
            set { raport = value; }
        }

        public void StartThread()
        {
            // zablokowanie wszystkich kontrolek
            
            airplaneThread = new Thread(new ThreadStart(Actualize));
            airplaneThread.Start();
        }

        public void EndThread()
        {
            // odblokowanie kontrolek
            if (airplaneThread != null)
            {
                endEvent.Set();
                airplaneThread.Abort();
            }
        }

        //metoda do wywołania w wątku
        public void Actualize()
        {
            endEvent = new ManualResetEvent(false);
            double[] state = new double[5]; // 0:theta 1:theta_zadane 2:q 3:alpha
            bool begin = true;
            double punishment = 0.0;
            Reinforcement.CCDecisionMaker dec = algorithms[threeVar,withRepeat];
            while (true)
            {
                if (endEvent != null && endEvent.WaitOne(0, false))
                    return;

                if (counter-- == 0)
                {
                    //tutaj wyznaczenie nowego "celu" 
                    
                    state[1] = Sampler.NextDouble()-0.5;
  
                    counter =(int) Sampler.SampleFromNormal(2.0*(1000/time),500.0/time); //srednio co 2 sekundy, niezaleznie od time
                }
                if (begin)
                {
                    
                    airplaneModel.CCStartInRandomState();
                    airplaneModel.CCGetCurrentState(ref state, ref state);
                   
                    dec.CCStartInState(state);
                    begin = false;
                }
               
                //obliczenie aktorem krytykiem decyzji
                if (counter_2-- == 0)
                {
                    dec.CCAdviseAction(ref steering);
                   steering[0] = steering[0] * 0.85;
                   //punishment = steering[0] > 1.4 ? (steering[0] - 1.4) : steering[0] < -1.4 ? ((-1.4) - steering[0]) : 0;
                   counter_2 = 5;
                }
                    
                    double[] steering_and_setpoint = { steering[0], state[1] };
             
                // ruszenie
                airplaneModel.CCMove(steering_and_setpoint);

               
                    //pobranie aktualnego stanu, ewentualne stwierdzenie konca epizodu
                    airplaneModel.CCGetCurrentState(ref state, ref state);
                    if (state[0] > 0.8 || state[0] < (-0.8)) //koniec epizodu
                    {
                        state[4] = 1;
                        begin = true;
                        counter = 0;
                        counter_2 = 0;
                    }
                    else
                        state[4] = 0;
                    //poprawa parametrow
                dec.CCThisHappened(0.1 - Math.Abs(state[1] - state[0]) , state); // pchaber (mod)
                    
             
                Thread.Sleep(time);
            }
        }

        public void Reset()
        {
            airplaneModel.CCStartInRandomState();
            HardReset();

        }

        public double AlgorithmBetaV
        {
            get
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        return AAC3.BetaVt;
                    else
                        return AACR3.BetaVt;
                }
                else
                {
                    if (withRepeat == 0)
                        return AAC4.BetaVt;
                    else
                        return AACR4.BetaVt;
                }

            }
            set {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        AAC3.BetaVt = value;
                    else
                        AACR3.BetaVt = value;
                }
                else
                {
                    if (withRepeat == 0)
                        AAC4.BetaVt = value;
                    else
                        AACR4.BetaVt = value;
                }
            }
        }

        public double AlgorithmDeviation
        {
            get
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        return AAC3.Deviation;
                    else
                        return AACR3.Deviation;
                }
                else
                {
                    if (withRepeat == 0)
                        return AAC4.Deviation;
                    else
                        return AACR4.Deviation;
                }

            }
            set
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        AAC3.Deviation = value;
                    else
                        AACR3.Deviation = value;
                }
                else
                {
                    if (withRepeat == 0)
                        AAC4.Deviation = value;
                    else
                        AACR4.Deviation = value;
                }
            }
        }

        public double AlgorithmBetaFi
        {
            get
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        return AAC3.BetaFit;
                    else
                        return AACR3.BetaFit;
                }
                else
                {
                    if (withRepeat == 0)
                        return AAC4.BetaFit;
                    else
                        return AACR4.BetaFit;
                }

            }
            set
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        AAC3.BetaFit = value;
                    else
                        AACR3.BetaFit = value;
                }
                else
                {
                    if (withRepeat == 0)
                        AAC4.BetaFit = value;
                    else
                        AACR4.BetaFit = value;
                }
            }
        }

        public double AlgorithmGamma
        {
            get
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        return AAC3.Gamma;
                    else
                        return AACR3.Gamma;
                }
                else
                {
                    if (withRepeat == 0)
                        return AAC4.Gamma;
                    else
                        return AACR4.Gamma;
                }

            }
            set
            {
                if (threeVar == 0)
                {
                    if (withRepeat == 0)
                        AAC3.Gamma = value;
                    else
                        AACR3.Gamma = value;
                }
                else
                {
                    if (withRepeat == 0)
                        AAC4.Gamma = value;
                    else
                        AACR4.Gamma = value;
                }
            }
        }
    }
}
